package com.oss.config.exception;

import com.oss.common.BaseResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author chengqiang
 * 全局异常处理
 * 部分特殊异常需要做特殊处理,
 *   例如:参数校验,登录认证
 * 特殊异常,需要在@ExceptionHandler中指定异常类型, 然后做对应的逻辑处理, 否则会被handleException方法统一捕获,响应的信息有可能不准确
 * 特殊逻辑处理, 放在handleException方法前面,放在后面虽然不影响结果
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    @Autowired
    HttpServletResponse response;

    /**
     * 参数校验异常
     * @param e 参数校验异常
     * @return 返回给客户端的提示信息
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public BaseResponse handleValidException(MethodArgumentNotValidException e) {
        //获取实体类定义的校验注解字段上的message作为异常信息，@NotBlank(message = "用户密码不能为空！")异常信息即为"用户密码不能为空！"
        List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
        String message = allErrors.stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(";"));
        List<String> msgList;
        msgList = Arrays.asList(message.split(";"));
        // 控制台打印异常
        e.printStackTrace();
        // 必须输出, 否则异常信息无法写入日志文件中, 只有上面的打印
        log.error(e.getMessage());
        return BaseResponse.error(msgList.get(0));
    }
    /**
     * 业务异常处理
     * @param e 异常
     * @return 返回异常信息
     */
    @ExceptionHandler(Exception.class)
    public BaseResponse handleException(Exception e) {
        // 收集异常信息并返回给客户端
        StringWriter sw = new StringWriter();
        e.printStackTrace(new PrintWriter(sw, true));
        String msg = sw.toString();
        // 控制台打印异常
        e.printStackTrace();
        // 必须输出, 否则异常信息无法写入日志文件中, 只有上面的打印
        log.error(msg);
        if (e.getCause() != null && StringUtils.isNotBlank(e.getCause().getMessage())){
            return BaseResponse.error(e.getCause().getMessage());
        } else {
            return BaseResponse.error(e.getMessage());
        }
    }

}